home *** CD-ROM | disk | FTP | other *** search
/ NeXT Education Software Sampler 1992 Fall / NeXT Education Software Sampler 1992 Fall.iso / Programming / Source / winterp-1.13 / src-server / xlisp / xleval.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-10-04  |  21.1 KB  |  911 lines

  1. /* -*-C-*-
  2. ********************************************************************************
  3. *
  4. * File:         xleval.c
  5. * RCS:          $Header: xleval.c,v 1.5 91/03/24 22:24:36 mayer Exp $
  6. * Description:  xlisp evaluator
  7. * Author:       David Michael Betz
  8. * Created:      
  9. * Modified:     Fri Oct  4 03:51:24 1991 (Niels Mayer) mayer@hplnpm
  10. * Language:     C
  11. * Package:      N/A
  12. * Status:       X11r5 contrib tape release
  13. *
  14. * WINTERP Copyright 1989, 1990, 1991 Hewlett-Packard Company (by Niels Mayer).
  15. * XLISP version 2.1, Copyright (c) 1989, by David Betz.
  16. *
  17. * Permission to use, copy, modify, distribute, and sell this software and its
  18. * documentation for any purpose is hereby granted without fee, provided that
  19. * the above copyright notice appear in all copies and that both that
  20. * copyright notice and this permission notice appear in supporting
  21. * documentation, and that the name of Hewlett-Packard and David Betz not be
  22. * used in advertising or publicity pertaining to distribution of the software
  23. * without specific, written prior permission.  Hewlett-Packard and David Betz
  24. * make no representations about the suitability of this software for any
  25. * purpose. It is provided "as is" without express or implied warranty.
  26. *
  27. * HEWLETT-PACKARD AND DAVID BETZ DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
  28. * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS,
  29. * IN NO EVENT SHALL HEWLETT-PACKARD NOR DAVID BETZ BE LIABLE FOR ANY SPECIAL,
  30. * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  31. * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  32. * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  33. * PERFORMANCE OF THIS SOFTWARE.
  34. *
  35. * See ./winterp/COPYRIGHT for information on contacting the authors.
  36. * Please send modifications, improvements and bugfixes to mayer@hplabs.hp.com
  37. * Post XLISP-specific questions/information to the newsgroup comp.lang.lisp.x
  38. *
  39. ********************************************************************************
  40. */
  41. static char rcs_identity[] = "@(#)$Header: xleval.c,v 1.5 91/03/24 22:24:36 mayer Exp $";
  42.  
  43. #include "xlisp.h"
  44.  
  45. /* macro to check for lambda list keywords */
  46. #define iskey(s) ((s) == lk_optional \
  47.                || (s) == lk_rest \
  48.                || (s) == lk_key \
  49.                || (s) == lk_aux \
  50.                || (s) == lk_allow_other_keys)
  51.  
  52. /* macros to handle tracing */
  53. #define trenter(sym,argc,argv) {if (sym) doenter(sym,argc,argv);}
  54. #define trexit(sym,val) {if (sym) doexit(sym,val);}
  55.  
  56. /* external variables */
  57. extern LVAL xlenv,xlfenv,xldenv,xlvalue,true;
  58. extern LVAL lk_optional,lk_rest,lk_key,lk_aux,lk_allow_other_keys;
  59. extern LVAL s_evalhook,s_applyhook,s_tracelist;
  60. extern LVAL s_lambda,s_macro;
  61. extern LVAL s_unbound;
  62. extern int xlsample;
  63. extern char buf[];
  64.  
  65. /* forward declarations */
  66. FORWARD LVAL xlxeval();
  67. LOCAL FORWARD LVAL evalhook();    /* NPM: changed this to LOCAL */
  68. LOCAL FORWARD LVAL evform();    /* NPM: changed this to LOCAL */
  69. LOCAL FORWARD LVAL evfun();    /* NPM: changed this to LOCAL */
  70.  
  71. /* xleval - evaluate an xlisp expression (checking for *evalhook*) */
  72. LVAL xleval(expr)
  73.   LVAL expr;
  74. {
  75.     /* check for control codes */
  76.     if (--xlsample <= 0) {
  77.     xlsample = SAMPLE;
  78.     oscheck();
  79.     }
  80.  
  81.     /* check for *evalhook* */
  82.     if (getvalue(s_evalhook))
  83.     return (evalhook(expr));
  84.  
  85.     /* check for nil */
  86.     if (null(expr))
  87.     return (NIL);
  88.  
  89.     /* dispatch on the node type */
  90.     switch (ntype(expr)) {
  91.     case CONS:
  92.     return (evform(expr));
  93.     case SYMBOL:
  94.     return (xlgetvalue(expr));
  95.     default:
  96.     return (expr);
  97.     }
  98. }
  99.  
  100. /* xlevalenv - evaluate an expression in a specified environment */
  101. LVAL xlevalenv(expr,env,fenv)
  102.   LVAL expr,env,fenv;
  103. {
  104.     LVAL oldenv,oldfenv,val;
  105.  
  106.     /* protect some pointers */
  107.     xlstkcheck(2);
  108.     xlsave(oldenv);
  109.     xlsave(oldfenv);
  110.  
  111.     /* establish the new environment */
  112.     oldenv = xlenv;
  113.     oldfenv = xlfenv;
  114.     xlenv = env;
  115.     xlfenv = fenv;
  116.  
  117.     /* evaluate the expression */
  118.     val = xleval(expr);
  119.  
  120.     /* restore the environment */
  121.     xlenv = oldenv;
  122.     xlfenv = oldfenv;
  123.  
  124.     /* restore the stack */
  125.     xlpopn(2);
  126.  
  127.     /* return the result value */
  128.     return (val);
  129. }
  130.  
  131. /* xlxeval - evaluate an xlisp expression (bypassing *evalhook*) */
  132. LVAL xlxeval(expr)
  133.   LVAL expr;
  134. {
  135.     /* check for nil */
  136.     if (null(expr))
  137.     return (NIL);
  138.  
  139.     /* dispatch on node type */
  140.     switch (ntype(expr)) {
  141.     case CONS:
  142.     return (evform(expr));
  143.     case SYMBOL:
  144.     return (xlgetvalue(expr));
  145.     default:
  146.     return (expr);
  147.     }
  148. }
  149.  
  150. /* xlapply - apply a function to arguments (already on the stack) */
  151. LVAL xlapply(argc)
  152.   int argc;
  153. {
  154.     LVAL *oldargv,fun,val;
  155.     int oldargc;
  156.     
  157.     /* get the function */
  158.     fun = xlfp[1];
  159.  
  160.     /* get the functional value of symbols */
  161.     if (symbolp(fun)) {
  162.     while ((val = getfunction(fun)) == s_unbound)
  163.         xlfunbound(fun);
  164.     fun = xlfp[1] = val;
  165.     }
  166.  
  167.     /* check for nil */
  168.     if (null(fun))
  169.     xlerror("bad function",fun);
  170.  
  171.     /* dispatch on node type */
  172.     switch (ntype(fun)) {
  173.     case SUBR:
  174.     oldargc = xlargc;
  175.     oldargv = xlargv;
  176.     xlargc = argc;
  177.     xlargv = xlfp + 3;
  178.     val = (*getsubr(fun))();
  179.     xlargc = oldargc;
  180.     xlargv = oldargv;
  181.     break;
  182.     case CONS:
  183.     if (!consp(cdr(fun)))
  184.         xlerror("bad function",fun);
  185.     if (car(fun) == s_lambda)
  186.         fun = xlclose(NIL,
  187.                       s_lambda,
  188.                       car(cdr(fun)),
  189.                       cdr(cdr(fun)),
  190.                       xlenv,xlfenv);
  191.     else
  192.         xlerror("bad function",fun);
  193.     /**** fall through into the next case ****/
  194.     case CLOSURE:
  195.     if (gettype(fun) != s_lambda)
  196.         xlerror("bad function",fun);
  197.     val = evfun(fun,argc,xlfp+3);
  198.     break;
  199.     default:
  200.     xlerror("bad function",fun);
  201.     }
  202.  
  203.     /* remove the call frame */
  204.     xlsp = xlfp;
  205.     xlfp = xlfp - (int)getfixnum(*xlfp);
  206.  
  207.     /* return the function value */
  208.     return (val);
  209. }
  210.  
  211. /* evform - evaluate a form */
  212. LOCAL LVAL evform(form)
  213.   LVAL form;
  214. {
  215.     LVAL fun,args,val,type;
  216.     LVAL tracing=NIL;
  217.     LVAL *argv;
  218.     int argc;
  219.  
  220.     /* protect some pointers */
  221.     xlstkcheck(2);
  222.     xlsave(fun);
  223.     xlsave(args);
  224.  
  225.     /* get the function and the argument list */
  226.     fun = car(form);
  227.     args = cdr(form);
  228.  
  229.     /* get the functional value of symbols */
  230.     if (symbolp(fun)) {
  231.     if (getvalue(s_tracelist) && member(fun,getvalue(s_tracelist)))
  232.         tracing = fun;
  233.     fun = xlgetfunction(fun);
  234.     }
  235.  
  236.     /* check for nil */
  237.     if (null(fun))
  238.     xlerror("bad function",NIL);
  239.  
  240.     /* dispatch on node type */
  241.     switch (ntype(fun)) {
  242.     case SUBR:
  243.     argv = xlargv;
  244.     argc = xlargc;
  245.     xlargc = evpushargs(fun,args);
  246.     xlargv = xlfp + 3;
  247.     trenter(tracing,xlargc,xlargv);
  248.     val = (*getsubr(fun))();
  249.     trexit(tracing,val);
  250.     xlsp = xlfp;
  251.     xlfp = xlfp - (int)getfixnum(*xlfp);
  252.     xlargv = argv;
  253.     xlargc = argc;
  254.     break;
  255.     case FSUBR:
  256.     argv = xlargv;
  257.     argc = xlargc;
  258.     xlargc = pushargs(fun,args);
  259.     xlargv = xlfp + 3;
  260.     val = (*getsubr(fun))();
  261.     xlsp = xlfp;
  262.     xlfp = xlfp - (int)getfixnum(*xlfp);
  263.     xlargv = argv;
  264.     xlargc = argc;
  265.     break;
  266.     case CONS:
  267.     if (!consp(cdr(fun)))
  268.         xlerror("bad function",fun);
  269.     if ((type = car(fun)) == s_lambda)
  270.          fun = xlclose(NIL,
  271.                        s_lambda,
  272.                        car(cdr(fun)),
  273.                        cdr(cdr(fun)),
  274.                        xlenv,xlfenv);
  275.     else
  276.         xlerror("bad function",fun);
  277.     /**** fall through into the next case ****/
  278.     case CLOSURE:
  279.     if (gettype(fun) == s_lambda) {
  280.         argc = evpushargs(fun,args);
  281.         argv = xlfp + 3;
  282.         trenter(tracing,argc,argv);
  283.         val = evfun(fun,argc,argv);
  284.         trexit(tracing,val);
  285.         xlsp = xlfp;
  286.         xlfp = xlfp - (int)getfixnum(*xlfp);
  287.     }
  288.     else {
  289.         macroexpand(fun,args,&fun);
  290.         val = xleval(fun);
  291.     }
  292.     break;
  293.     default:
  294.     xlerror("bad function",fun);
  295.     }
  296.  
  297.     /* restore the stack */
  298.     xlpopn(2);
  299.  
  300.     /* return the result value */
  301.     return (val);
  302. }
  303.  
  304. /* xlexpandmacros - expand macros in a form */
  305. LVAL xlexpandmacros(form)
  306.   LVAL form;
  307. {
  308.     LVAL fun,args;
  309.     
  310.     /* protect some pointers */
  311.     xlstkcheck(3);
  312.     xlprotect(form);
  313.     xlsave(fun);
  314.     xlsave(args);
  315.  
  316.     /* expand until the form isn't a macro call */
  317.     while (consp(form)) {
  318.     fun = car(form);        /* get the macro name */
  319.     args = cdr(form);        /* get the arguments */
  320.     if (!symbolp(fun) || !fboundp(fun))
  321.         break;
  322.     fun = xlgetfunction(fun);    /* get the expansion function */
  323.     if (!macroexpand(fun,args,&form))
  324.         break;
  325.     }
  326.  
  327.     /* restore the stack and return the expansion */
  328.     xlpopn(3);
  329.     return (form);
  330. }
  331.  
  332. /* macroexpand - expand a macro call */
  333. int macroexpand(fun,args,pval)
  334.   LVAL fun,args,*pval;
  335. {
  336.     LVAL *argv;
  337.     int argc;
  338.     
  339.     /* make sure it's really a macro call */
  340.     if (!closurep(fun) || gettype(fun) != s_macro)
  341.     return (FALSE);
  342.     
  343.     /* call the expansion function */
  344.     argc = pushargs(fun,args);
  345.     argv = xlfp + 3;
  346.     *pval = evfun(fun,argc,argv);
  347.     xlsp = xlfp;
  348.     xlfp = xlfp - (int)getfixnum(*xlfp);
  349.     return (TRUE);
  350. }
  351.  
  352. /* evalhook - call the evalhook function */
  353. LOCAL LVAL evalhook(expr)
  354.   LVAL expr;
  355. {
  356.     LVAL *newfp,olddenv,val;
  357.  
  358.     /* create the new call frame */
  359.     newfp = xlsp;
  360.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  361.     pusharg(getvalue(s_evalhook));
  362.     pusharg(cvfixnum((FIXTYPE)2));
  363.     pusharg(expr);
  364.     pusharg(cons(xlenv,xlfenv));
  365.     xlfp = newfp;
  366.  
  367.     /* rebind the hook functions to nil */
  368.     olddenv = xldenv;
  369.     xldbind(s_evalhook,NIL);
  370.     xldbind(s_applyhook,NIL);
  371.  
  372.     /* call the hook function */
  373.     val = xlapply(2);
  374.  
  375.     /* unbind the symbols */
  376.     xlunbind(olddenv);
  377.  
  378.     /* return the value */
  379.     return (val);
  380. }
  381.  
  382. /* evpushargs - evaluate and push a list of arguments */
  383. LOCAL int evpushargs(fun,args)
  384.   LVAL fun,args;
  385. {
  386.     LVAL *newfp;
  387.     int argc;
  388.     
  389.     /* protect the argument list */
  390.     xlprot1(args);
  391.  
  392.     /* build a new argument stack frame */
  393.     newfp = xlsp;
  394.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  395.     pusharg(fun);
  396.     pusharg(NIL); /* will be argc */
  397.  
  398.     /* evaluate and push each argument */
  399.     for (argc = 0; consp(args); args = cdr(args), ++argc)
  400.     pusharg(xleval(car(args)));
  401.  
  402.     /* establish the new stack frame */
  403.     newfp[2] = cvfixnum((FIXTYPE)argc);
  404.     xlfp = newfp;
  405.     
  406.     /* restore the stack */
  407.     xlpop();
  408.  
  409.     /* return the number of arguments */
  410.     return (argc);
  411. }
  412.  
  413. /* pushargs - push a list of arguments */
  414. int pushargs(fun,args)
  415.   LVAL fun,args;
  416. {
  417.     LVAL *newfp;
  418.     int argc;
  419.     
  420.     /* build a new argument stack frame */
  421.     newfp = xlsp;
  422.     pusharg(cvfixnum((FIXTYPE)(newfp - xlfp)));
  423.     pusharg(fun);
  424.     pusharg(NIL); /* will be argc */
  425.  
  426.     /* push each argument */
  427.     for (argc = 0; consp(args); args = cdr(args), ++argc)
  428.     pusharg(car(args));
  429.  
  430.     /* establish the new stack frame */
  431.     newfp[2] = cvfixnum((FIXTYPE)argc);
  432.     xlfp = newfp;
  433.  
  434.     /* return the number of arguments */
  435.     return (argc);
  436. }
  437.  
  438. /* makearglist - make a list of the remaining arguments */
  439. LVAL makearglist(argc,argv)
  440.   int argc; LVAL *argv;
  441. {
  442.     LVAL list,this,last;
  443.     xlsave1(list);
  444.     for (last = NIL; --argc >= 0; last = this) {
  445.     this = cons(*argv++,NIL);
  446.     if (last) rplacd(last,this);
  447.     else list = this;
  448.      /* last = this; */ /* NPM: commented this out at request of jsp@glia.biostr.washington.edu (Jeff Prothero) */ 
  449.     }
  450.     xlpop();
  451.     return (list);
  452. }
  453.  
  454. /* evfun - evaluate a function */
  455. LOCAL LVAL evfun(fun,argc,argv)
  456.   LVAL fun; int argc; LVAL *argv;
  457. {
  458.     LVAL oldenv,oldfenv,cptr,name,val;
  459.     CONTEXT cntxt;
  460.  
  461.     /* protect some pointers */
  462.     xlstkcheck(3);
  463.     xlsave(oldenv);
  464.     xlsave(oldfenv);
  465.     xlsave(cptr);
  466.  
  467.     /* create a new environment frame */
  468.     oldenv = xlenv;
  469.     oldfenv = xlfenv;
  470. #ifdef WINTERP            /* note: changed getenv()-->getenvt() due to name conflict with stdlib.h:getenv() */
  471.     xlenv = xlframe(getenvt(fun));
  472. #else
  473.     xlenv = xlframe(getenv(fun));
  474. #endif                /* WINTERP */
  475.     xlfenv = getfenv(fun);
  476.  
  477.     /* bind the formal parameters */
  478.     xlabind(fun,argc,argv);
  479.  
  480.     /* setup the implicit block */
  481.     if (name = getname(fun))
  482.     xlbegin(&cntxt,CF_RETURN,name);
  483.  
  484.     /* execute the block */
  485.     if (name && setjmp(cntxt.c_jmpbuf))
  486.     val = xlvalue;
  487.     else
  488.     for (val = NIL, cptr = getbody(fun); consp(cptr); cptr = cdr(cptr))
  489.         val = xleval(car(cptr));
  490.  
  491.     /* finish the block context */
  492.     if (name)
  493.     xlend(&cntxt);
  494.  
  495.     /* restore the environment */
  496.     xlenv = oldenv;
  497.     xlfenv = oldfenv;
  498.  
  499.     /* restore the stack */
  500.     xlpopn(3);
  501.  
  502.     /* return the result value */
  503.     return (val);
  504. }
  505.  
  506. /* xlclose - create a function closure */
  507. LVAL xlclose(name,type,fargs,body,env,fenv)
  508.   LVAL name,type,fargs,body,env,fenv;
  509. {
  510.     LVAL closure,key,arg,def,svar,new,last;
  511.     char keyname[STRMAX+2];
  512.  
  513.     /* protect some pointers */
  514.     xlsave1(closure);
  515.  
  516.     /* create the closure object */
  517.     closure = newclosure(name,type,env,fenv);
  518.     setlambda(closure,fargs);
  519.     setbody(closure,body);
  520.  
  521.     /* handle each required argument */
  522.     last = NIL;
  523.     while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
  524.  
  525.     /* make sure the argument is a symbol */
  526.     if (!symbolp(arg))
  527.         badarglist();
  528.  
  529.     /* create a new argument list entry */
  530.     new = cons(arg,NIL);
  531.  
  532.     /* link it into the required argument list */
  533.     if (last)
  534.         rplacd(last,new);
  535.     else
  536.         setargs(closure,new);
  537.     last = new;
  538.  
  539.     /* move the formal argument list pointer ahead */
  540.     fargs = cdr(fargs);
  541.     }
  542.  
  543.     /* check for the '&optional' keyword */
  544.     if (consp(fargs) && car(fargs) == lk_optional) {
  545.     fargs = cdr(fargs);
  546.  
  547.     /* handle each optional argument */
  548.     last = NIL;
  549.     while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
  550.  
  551.         /* get the default expression and specified-p variable */
  552.         def = svar = NIL;
  553.         if (consp(arg)) {
  554.         if (def = cdr(arg))
  555.             if (consp(def)) {
  556.             if (svar = cdr(def))
  557.                 if (consp(svar)) {
  558.                 svar = car(svar);
  559.                 if (!symbolp(svar))
  560.                     badarglist();
  561.                 }
  562.                 else
  563.                 badarglist();
  564.             def = car(def);
  565.             }
  566.             else
  567.             badarglist();
  568.         arg = car(arg);
  569.         }
  570.  
  571.         /* make sure the argument is a symbol */
  572.         if (!symbolp(arg))
  573.         badarglist();
  574.  
  575.         /* create a fully expanded optional expression */
  576.         new = cons(cons(arg,cons(def,cons(svar,NIL))),NIL);
  577.  
  578.         /* link it into the optional argument list */
  579.         if (last)
  580.         rplacd(last,new);
  581.         else
  582.         setoargs(closure,new);
  583.         last = new;
  584.         
  585.         /* move the formal argument list pointer ahead */
  586.         fargs = cdr(fargs);
  587.     }
  588.     }
  589.  
  590.     /* check for the '&rest' keyword */
  591.     if (consp(fargs) && car(fargs) == lk_rest) {
  592.     fargs = cdr(fargs);
  593.  
  594.     /* get the &rest argument */
  595.     if (consp(fargs) && (arg = car(fargs)) && !iskey(arg) && symbolp(arg))
  596.         setrest(closure,arg);
  597.     else
  598.         badarglist();
  599.  
  600.     /* move the formal argument list pointer ahead */
  601.     fargs = cdr(fargs);
  602.     }
  603.  
  604.     /* check for the '&key' keyword */
  605.     if (consp(fargs) && car(fargs) == lk_key) {
  606.     fargs = cdr(fargs);
  607.  
  608.      /* handle each key argument */
  609.     last = NIL;
  610.     while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
  611.  
  612.         /* get the default expression and specified-p variable */
  613.         def = svar = NIL;
  614.         if (consp(arg)) {
  615.         if (def = cdr(arg))
  616.             if (consp(def)) {
  617.             if (svar = cdr(def))
  618.                 if (consp(svar)) {
  619.                 svar = car(svar);
  620.                 if (!symbolp(svar))
  621.                     badarglist();
  622.                 }
  623.                 else
  624.                 badarglist();
  625.             def = car(def);
  626.             }
  627.             else
  628.             badarglist();
  629.         arg = car(arg);
  630.         }
  631.  
  632.         /* get the keyword and the variable */
  633.         if (consp(arg)) {
  634.         key = car(arg);
  635.         if (!symbolp(key))
  636.             badarglist();
  637.         if (arg = cdr(arg))
  638.             if (consp(arg))
  639.             arg = car(arg);
  640.             else
  641.             badarglist();
  642.         }
  643.         else if (symbolp(arg)) {
  644.         strcpy(keyname,":");
  645.         strcat(keyname,getstring(getpname(arg)));
  646.         key = xlenter(keyname);
  647.         }
  648.  
  649.         /* make sure the argument is a symbol */
  650.         if (!symbolp(arg))
  651.         badarglist();
  652.  
  653.         /* create a fully expanded key expression */
  654.         new = cons(cons(key,cons(arg,cons(def,cons(svar,NIL)))),NIL);
  655.  
  656.         /* link it into the optional argument list */
  657.         if (last)
  658.         rplacd(last,new);
  659.         else
  660.         setkargs(closure,new);
  661.         last = new;
  662.  
  663.         /* move the formal argument list pointer ahead */
  664.         fargs = cdr(fargs);
  665.     }
  666.     }
  667.  
  668.     /* check for the '&allow-other-keys' keyword */
  669.     if (consp(fargs) && car(fargs) == lk_allow_other_keys)
  670.     fargs = cdr(fargs);    /* this is the default anyway */
  671.  
  672.     /* check for the '&aux' keyword */
  673.     if (consp(fargs) && car(fargs) == lk_aux) {
  674.     fargs = cdr(fargs);
  675.  
  676.     /* handle each aux argument */
  677.     last = NIL;
  678.     while (consp(fargs) && (arg = car(fargs)) && !iskey(arg)) {
  679.  
  680.         /* get the initial value */
  681.         def = NIL;
  682.         if (consp(arg)) {
  683.         if (def = cdr(arg))
  684.             if (consp(def))
  685.             def = car(def);
  686.             else
  687.             badarglist();
  688.         arg = car(arg);
  689.         }
  690.  
  691.         /* make sure the argument is a symbol */
  692.         if (!symbolp(arg))
  693.         badarglist();
  694.  
  695.         /* create a fully expanded aux expression */
  696.         new = cons(cons(arg,cons(def,NIL)),NIL);
  697.  
  698.         /* link it into the aux argument list */
  699.         if (last)
  700.         rplacd(last,new);
  701.         else
  702.         setaargs(closure,new);
  703.         last = new;
  704.  
  705.         /* move the formal argument list pointer ahead */
  706.         fargs = cdr(fargs);
  707.     }
  708.     }
  709.  
  710.     /* make sure this is the end of the formal argument list */
  711.     if (fargs)
  712.     badarglist();
  713.  
  714.     /* restore the stack */
  715.     xlpop();
  716.  
  717.     /* return the new closure */
  718.     return (closure);
  719. }
  720.  
  721. /* xlabind - bind the arguments for a function */
  722. xlabind(fun,argc,argv)
  723.   LVAL fun; int argc; LVAL *argv;
  724. {
  725.     LVAL *kargv,fargs,key,arg,def,svar,p;
  726.     int rargc,kargc;
  727.     
  728.     /* protect some pointers */
  729.     xlsave1(def);
  730.  
  731.     /* bind each required argument */
  732.     for (fargs = getargs(fun); fargs; fargs = cdr(fargs)) {
  733.  
  734.     /* make sure there is an actual argument */
  735.     if (--argc < 0)
  736.         xlfail("too few arguments");
  737.  
  738.     /* bind the formal variable to the argument value */
  739.     xlbind(car(fargs),*argv++);
  740.     }
  741.  
  742.     /* bind each optional argument */
  743.     for (fargs = getoargs(fun); fargs; fargs = cdr(fargs)) {
  744.  
  745.     /* get argument, default and specified-p variable */
  746.     p = car(fargs);
  747.     arg = car(p); p = cdr(p);
  748.     def = car(p); p = cdr(p);
  749.     svar = car(p);
  750.  
  751.     /* bind the formal variable to the argument value */
  752.     if (--argc >= 0) {
  753.         xlbind(arg,*argv++);
  754.         if (svar) xlbind(svar,true);
  755.     }
  756.  
  757.     /* bind the formal variable to the default value */
  758.     else {
  759.         if (def) def = xleval(def);
  760.         xlbind(arg,def);
  761.         if (svar) xlbind(svar,NIL);
  762.     }
  763.     }
  764.  
  765.     /* save the count of the &rest of the argument list */
  766.     rargc = argc;
  767.     
  768.     /* handle '&rest' argument */
  769.     if (arg = getrest(fun)) {
  770.     def = makearglist(argc,argv);
  771.     xlbind(arg,def);
  772.     argc = 0;
  773.     }
  774.  
  775.     /* handle '&key' arguments */
  776.     if (fargs = getkargs(fun)) {
  777.     for (; fargs; fargs = cdr(fargs)) {
  778.  
  779.         /* get keyword, argument, default and specified-p variable */
  780.         p = car(fargs);
  781.         key = car(p); p = cdr(p);
  782.         arg = car(p); p = cdr(p);
  783.         def = car(p); p = cdr(p);
  784.         svar = car(p);
  785.  
  786.         /* look for the keyword in the actual argument list */
  787.         for (kargv = argv, kargc = rargc; (kargc -= 2) >= 0; kargv += 2)
  788.         if (*kargv == key)
  789.             break;
  790.  
  791.         /* bind the formal variable to the argument value */
  792.         if (kargc >= 0) {
  793.         xlbind(arg,*++kargv);
  794.         if (svar) xlbind(svar,true);
  795.         }
  796.  
  797.         /* bind the formal variable to the default value */
  798.         else {
  799.         if (def) def = xleval(def);
  800.         xlbind(arg,def);
  801.         if (svar) xlbind(svar,NIL);
  802.         }
  803.     }
  804.     argc = 0;
  805.     }
  806.  
  807.     /* check for the '&aux' keyword */
  808.     for (fargs = getaargs(fun); fargs; fargs = cdr(fargs)) {
  809.  
  810.     /* get argument and default */
  811.     p = car(fargs);
  812.     arg = car(p); p = cdr(p);
  813.     def = car(p);
  814.  
  815.     /* bind the auxiliary variable to the initial value */
  816.     if (def) def = xleval(def);
  817.     xlbind(arg,def);
  818.     }
  819.  
  820.     /* make sure there aren't too many arguments */
  821.     if (argc > 0)
  822.     xlfail("too many arguments");
  823.  
  824.     /* restore the stack */
  825.     xlpop();
  826. }
  827.  
  828. /* doenter - print trace information on function entry */
  829. LOCAL doenter(sym,argc,argv)
  830.   LVAL sym; int argc; LVAL *argv;
  831. {
  832.     extern int xltrcindent;
  833.     int i;
  834.     
  835.     /* indent to the current trace level */
  836.     for (i = 0; i < xltrcindent; ++i)
  837.     trcputstr(" ");
  838.     ++xltrcindent;
  839.  
  840.     /* display the function call */
  841.     sprintf(buf,"Entering: %s, Argument list: (",getstring(getpname(sym)));
  842.     trcputstr(buf);
  843.     while (--argc >= 0) {
  844.     trcprin1(*argv++);
  845.     if (argc) trcputstr(" ");
  846.     }
  847.     trcputstr(")\n");
  848. }
  849.  
  850. /* doexit - print trace information for function/macro exit */
  851. LOCAL doexit(sym,val)
  852.   LVAL sym,val;
  853. {
  854.     extern int xltrcindent;
  855.     int i;
  856.     
  857.     /* indent to the current trace level */
  858.     --xltrcindent;
  859.     for (i = 0; i < xltrcindent; ++i)
  860.     trcputstr(" ");
  861.     
  862.     /* display the function value */
  863.     sprintf(buf,"Exiting: %s, Value: ",getstring(getpname(sym)));
  864.     trcputstr(buf);
  865.     trcprin1(val);
  866.     trcputstr("\n");
  867. }
  868.  
  869. /* member - is 'x' a member of 'list'? */
  870. LOCAL int member(x,list)
  871.   LVAL x,list;
  872. {
  873.     for (; consp(list); list = cdr(list))
  874.     if (x == car(list))
  875.         return (TRUE);
  876.     return (FALSE);
  877. }
  878.  
  879. /* xlunbound - signal an unbound variable error */
  880. xlunbound(sym)
  881.   LVAL sym;
  882. {
  883.     xlcerror("try evaluating symbol again","unbound variable",sym);
  884. }
  885.  
  886. /* xlfunbound - signal an unbound function error */
  887. xlfunbound(sym)
  888.   LVAL sym;
  889. {
  890.     xlcerror("try evaluating symbol again","unbound function",sym);
  891. }
  892.  
  893. /* xlstkoverflow - signal a stack overflow error */
  894. xlstkoverflow()
  895. {
  896.     xlabort("evaluation stack overflow");
  897. }
  898.  
  899. /* xlargstkoverflow - signal an argument stack overflow error */
  900. xlargstkoverflow()
  901. {
  902.     xlabort("argument stack overflow");
  903. }
  904.  
  905. /* badarglist - report a bad argument list error */
  906. LOCAL badarglist()
  907. {
  908.     xlfail("bad formal argument list");
  909. }
  910.